/**
 * 
 */
package com.mc.oshi;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.ComputerSystem;
import oshi.hardware.Firmware;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HWPartition;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.hardware.NetworkIF;
import oshi.hardware.Sensors;
import oshi.software.os.FileSystem;
import oshi.software.os.NetworkParams;
import oshi.software.os.OSFileStore;
import oshi.software.os.OSProcess;
import oshi.software.os.OperatingSystem;
import oshi.util.FormatUtil;
import oshi.util.Util;

/**
 * @author w.weizhen
 * 监测机器资源信息
 */
public class OshiMonitor {

    /**
     * @param args
     */
    public static void main(String[] args) {
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();
        OperatingSystem os = si.getOperatingSystem();
        
//        while (true){
            try {
                cpu(hal.getProcessor(), hal.getSensors());
                memory(hal.getMemory());
                system(hal.getComputerSystem());
                disk(hal.getDiskStores(), os.getFileSystem());
                jvm(os, hal.getMemory());
                network(hal.getNetworkIFs(), os.getNetworkParams());
//                TimeUnit.SECONDS.sleep(5);//等待五秒钟
            }catch (Exception e){
                e.printStackTrace();
            }
//        }
    }
    private static void cpu(CentralProcessor processor, Sensors sensors) throws InterruptedException {
        System.out.println("----------------cpu信息----------------");
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(1000);//等待一段时间，确保数据获取。
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        System.out.println("cpu系统使用率:" + new DecimalFormat("#.##%").format(cSys * 1.0 / totalCpu));
        System.out.println("cpu用户使用率:" + new DecimalFormat("#.##%").format(user * 1.0 / totalCpu));
        System.out.println("cpu当前等待率:" + new DecimalFormat("#.##%").format(iowait * 1.0 / totalCpu));
        System.out.println("cpu当前使用率:" + new DecimalFormat("#.##%").format(1.0-(idle * 1.0 / totalCpu)));
        System.out.println("cpu个数:" + processor.getPhysicalPackageCount());
        System.out.println("cpu物理核心个数:" + processor.getPhysicalProcessorCount());
        System.out.println("cpu逻辑核心个数:" + processor.getLogicalProcessorCount());
        System.out.println("cpu标识符: " + processor.getProcessorIdentifier());
        System.out.println("cpu序列号: " + processor.getProcessorIdentifier().getProcessorID());
        
        System.out.println(String.format("cpu温度: %.1f°C%n", sensors.getCpuTemperature()));
        System.out.println("风扇转速:" + Arrays.toString(sensors.getFanSpeeds()));
        System.out.println(String.format("cpu电压: %.1fV%n", sensors.getCpuVoltage()));
    }

    public static void memory(GlobalMemory memory){
        System.out.println("----------------主机内存信息----------------");
        //总内存
        long totalByte = memory.getTotal();
        //剩余
        long acaliableByte = memory.getAvailable();
        System.out.println("总内存 = " + formatByte(totalByte));
        System.out.println("使用" + formatByte(totalByte-acaliableByte));
        System.out.println("剩余内存 = " + formatByte(acaliableByte));
        System.out.println("使用率：" + new DecimalFormat("#.##%").format((totalByte-acaliableByte)*1.0/totalByte));
    }

    public static void system(ComputerSystem computerSystem){
        System.out.println("----------------操作系统信息----------------");
        Properties props = System.getProperties();
        System.out.println("操作系统名 = " + props.getProperty("os.name"));
        System.out.println("版本 = " + props.getProperty("os.version"));
        System.out.println("系统架构 = " + props.getProperty("os.arch"));
        
        System.out.println("制造商 = " + computerSystem.getManufacturer());
        System.out.println("型号 = " + computerSystem.getModel());
        System.out.println("序列号 = " + computerSystem.getSerialNumber());
        
        Firmware firmware = computerSystem.getFirmware();
        System.out.println("制造商 = " + firmware.getManufacturer());
        System.out.println("名称: " + firmware.getName());
        System.out.println("描述: " + firmware.getDescription());
        System.out.println("版本: " + firmware.getVersion());
    }
    
    public static void disk(List<HWDiskStore> list, FileSystem fileSystem)
    {
        System.out.println("----------------磁盘信息----------------");
//        File[] files = File.listRoots();
//        for (File file : files) {
//            String total = new DecimalFormat("#.#").format(file.getTotalSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
//            String free = new DecimalFormat("#.#").format(file.getFreeSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
//            String un = new DecimalFormat("#.#").format(file.getUsableSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
//            String path = file.getPath();
//            System.out.println(path + "总:" + total + ",可用空间:" + un + ",空闲空间:" + free);
//        }
        
        for (HWDiskStore disk : list) {
            boolean readwrite = disk.getReads() > 0 || disk.getWrites() > 0;
            System.out.format(" %s: (model: %s - S/N: %s) size: %s, reads: %s (%s), writes: %s (%s), xfer: %s ms%n",
                    disk.getName(), disk.getModel(), disk.getSerial(),
                    disk.getSize() > 0 ? FormatUtil.formatBytesDecimal(disk.getSize()) : "?",
                    readwrite ? disk.getReads() : "?", readwrite ? FormatUtil.formatBytes(disk.getReadBytes()) : "?",
                    readwrite ? disk.getWrites() : "?", readwrite ? FormatUtil.formatBytes(disk.getWriteBytes()) : "?",
                    readwrite ? disk.getTransferTime() : "?");
            List<HWPartition> partitions = disk.getPartitions();
            if (partitions == null) {
                // TODO Remove when all OS's implemented
                continue;
            }
            for (HWPartition part : partitions) {
                System.out.format(" |-- %s: %s (%s) Maj:Min=%d:%d, size: %s%s%n", part.getIdentification(),
                        part.getName(), part.getType(), part.getMajor(), part.getMinor(),
                        FormatUtil.formatBytesDecimal(part.getSize()),
                        part.getMountPoint().isEmpty() ? "" : " @ " + part.getMountPoint());
            }
        }
        
        
        System.out.format(" File Descriptors: %d/%d%n", fileSystem.getOpenFileDescriptors(), fileSystem.getMaxFileDescriptors());
        List<OSFileStore> fsArray = fileSystem.getFileStores();
        for (OSFileStore fs : fsArray) {
            long usable = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            System.out.format(" %s (%s) [%s] %s of %s free (%.1f%%) is %s "
                            + (fs.getLogicalVolume() != null && fs.getLogicalVolume().length() > 0 ? "[%s]" : "%s")
                            + " and is mounted at %s%n",
                    fs.getName(), fs.getDescription().isEmpty() ? "file system" : fs.getDescription(), fs.getType(),
                    FormatUtil.formatBytes(usable), FormatUtil.formatBytes(fs.getTotalSpace()), 100d * usable / total,
                    fs.getVolume(), fs.getLogicalVolume(), fs.getMount());
        }
    }

    public static void jvm(OperatingSystem os, GlobalMemory memory){
        System.out.println("----------------jvm信息----------------");
        Properties props = System.getProperties();
        Runtime runtime = Runtime.getRuntime();
        
        //jvm总内存
        long jvmTotalMemoryByte = runtime.totalMemory();
        //jvm最大可申请
        long jvmMaxMoryByte = runtime.maxMemory();
        //空闲空间
        long freeMemoryByte = runtime.freeMemory();
        System.out.println("jvm最大总量 = " + formatByte(jvmMaxMoryByte));
        System.out.println("jvm内存总量 = " + formatByte(jvmTotalMemoryByte));
        System.out.println("jvm已使用内存 = " + formatByte(jvmTotalMemoryByte-freeMemoryByte));
        System.out.println("jvm剩余内存 = " + formatByte(freeMemoryByte));
        System.out.println("jvm内存使用率 = " + new DecimalFormat("#.##%").format((jvmTotalMemoryByte-freeMemoryByte)*1.0/jvmTotalMemoryByte));
        System.out.println("java版本 = " + props.getProperty("java.version"));
        System.out.println("jdkHome = " + props.getProperty("java.home"));
        
        System.out.println("进程: " + os.getProcessCount() + ", 线程: " + os.getThreadCount());
        // Sort by highest CPU
        List<OSProcess> procs = os.getProcesses(null, OperatingSystem.ProcessSorting.CPU_DESC, 10);
        for (OSProcess process : procs) {
            // 进程名称，工作目录，PID，CPU
            System.out.println(String.format("进程名称:%s 工作目录:%s PID: %d CPU:%.3f", process.getName(),
                    process.getCurrentWorkingDirectory(), process.getProcessID(),
                    process.getProcessCpuLoadCumulative()));
        }
        
        MemoryMXBean bean = ManagementFactory.getMemoryMXBean();
        MemoryUsage memoryUsage = bean.getHeapMemoryUsage();
        System.out.println(memoryUsage.getUsed());
        
        System.out.println(System.getProperty("user.dir"));
        System.out.println(System.getProperty("catalina.home"));
    }
    
    public static void network(List<NetworkIF> networkIFs, NetworkParams networkParams)
    {
        System.out.println("----------------网络信息----------------");
        for (NetworkIF net : networkIFs) {
            System.out.format("网络设备: %s (%s)%n", net.getName(), net.getDisplayName());
            System.out.format("    MAC: %s %n", net.getMacaddr());
            System.out.format("    MTU: %s, Speed: %s %n", net.getMTU(), FormatUtil.formatValue(net.getSpeed(), "bps"));
            System.out.format("    IPv4: %s %n", Arrays.toString(net.getIPv4addr()));
            System.out.format("    IPv6: %s %n", Arrays.toString(net.getIPv6addr()));
            boolean hasData = net.getBytesRecv() > 0 || net.getBytesSent() > 0 || net.getPacketsRecv() > 0 || net.getPacketsSent() > 0;
            System.out.format("    吞吐量: 接受 %s/%s%s; 发送 %s/%s%s %n",
                hasData ? net.getPacketsRecv() + " packets" : "?",
                hasData ? FormatUtil.formatBytes(net.getBytesRecv()) : "?",
                hasData ? " (" + net.getInErrors() + " err)" : "",
                hasData ? net.getPacketsSent() + " packets" : "?",
                hasData ? FormatUtil.formatBytes(net.getBytesSent()) : "?",
                hasData ? " (" + net.getOutErrors() + " err)" : "");
            System.out.println();
        }
        
        System.out.format("主机名: %s%n", networkParams.getHostName());
        System.out.format("域名: %s%n", networkParams.getDomainName());
        System.out.format("DNS服务器: %s%n", Arrays.toString(networkParams.getDnsServers()));
        System.out.format("IPv4网关: %s%n", networkParams.getIpv4DefaultGateway());
        System.out.format("IPv6网关: %s%n", networkParams.getIpv6DefaultGateway());
    }
    
    public static String formatByte(long byteNumber){
        //换算单位
        double FORMAT = 1024.0;
        double kbNumber = byteNumber/FORMAT;
        if(kbNumber<FORMAT){
            return new DecimalFormat("#.##KB").format(kbNumber);
        }
        double mbNumber = kbNumber/FORMAT;
        if(mbNumber<FORMAT){
            return new DecimalFormat("#.##MB").format(mbNumber);
        }
        double gbNumber = mbNumber/FORMAT;
        if(gbNumber<FORMAT){
            return new DecimalFormat("#.##GB").format(gbNumber);
        }
        double tbNumber = gbNumber/FORMAT;
        return new DecimalFormat("#.##TB").format(tbNumber);
    }
}